﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using Newtonsoft.Json;
using System.Net;
using Frankfort.Threading.Internal;
using System.Net.NetworkInformation;
using SerializeEx;

class Il2cppPatchInfo
{
    public string[] urls = null;
    public string file_name = null;
	public uint size = 0;
}

class ResourceInfo
{
    public string[] urls = null;
    public string config_md5 = null;
    public BundleVersionConfig config;
}

class ExternalResourceInfo
{
//    public int version;
    public string md5;
    public string url;
    public uint size;
}

public class BoolJsonConvertor: JsonConverter
{
    public override bool CanConvert(System.Type objectType)  
    {
        return true;
    }

    public override object ReadJson(JsonReader reader, System.Type objectType, object existingValue, JsonSerializer serializer)  
    {  
        try
        {
            return serializer.Deserialize<int>(reader) == 0? false: true;
        }
        catch(System.Exception e)
        {
            Debug.LogException(e);
        }
        return false;
    }  

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)  
    {
        try
        {
            serializer.Serialize(writer, value);
        }
        catch(System.Exception e)
        {
            Debug.LogException(e);
        }
    }
}


class ErrorCode
{
    public const int RECEIVE_ERROR_DATA = -3;
    public const int CLIENT_NEED_UPDATE = -2;
    public const int UNKNOWN_ERROR = -1;
    public const int NO_ERROR = 0;
}

public class NoticeInfo
{
    public string md5;
    public string content;
}

class GetLatestGameInfoResponse
{
    public string error;
    public int error_code;
    public ResourceInfo asset_bundle_info;
    public ExternalResourceInfo external_resource_info;
	public Il2cppPatchInfo il2cpp_patch_info;
    // public ServerInfo[] server_infos;
}

public class MyLuaResLoader: LuaResLoader
{
    string GetCpuRelatedPath(string path)
    {
        if(!Application.isEditor)
        {
            int intPtrSize = System.IntPtr.Size;
            if(intPtrSize == 4)
            {
                path = luaDir + "/32/" + path;
                return path;
            }
            else if(intPtrSize == 8)
            {
                path = luaDir + "/64/" + path;
                return path;
            }
        }

        
        return luaDir + "/" + path;
    }
    public override byte[] LoadResource(string path)
    {
        string cpuPath = GetCpuRelatedPath(path);
        byte[] data = ResourceManager.LoadBytes(cpuPath, true);
        
        if(data != null)
        {
            return data;
        }

        path = luaDir + "/" + path;
        return ResourceManager.LoadBytes(path, true);

        // path = luaDir + "/" + path;
        // byte[] data = Login.LoadExternalBytes(path);
        // if (data != null)
        // {
        //     return data;
        // }

        // TextAsset text = ResourceManager.LoadAsset(path, typeof(TextAsset)) as TextAsset;
        // if (text != null)
        // {
        //     data = text.bytes;
        //     Resources.UnloadAsset(text);
        //     return data;
        // }
        // return null;
    }
}


class BundleHttpRedirectHelper: HttpRedirectHelper
{
    string[] urls;

    public BundleHttpRedirectHelper(string[] urls)
    {
        this.urls = urls;
    }

    public override string ChangeUrl(string url, int hostIndex)
    {
        int count = Count();
        if(hostIndex < 0 || hostIndex >= count)
        {
            return url;
        }

        string oldHostUrl = urls[0];

        int realHostIndex = hostIndex + 1;
        string newHostUrl = urls[realHostIndex % urls.Length];

        if (newHostUrl == oldHostUrl)
        {
            return url;
        }
        
        url = url.Replace(oldHostUrl, newHostUrl);
        return url;
    }

    public override int Count()
    {
        return urls == null? 0: urls.Length;
    }
}

public class Login : LuaMonoBehaviour
{
    static bool inited = false;
    static bool globalInited = false;
    static WindowProxy exitWindowProxy;

    // public MediaPlayerCtrlEx videoMovie;
    public GameObject skipBtn;
    // public RandomMovie loginMovie;
    public GameObject loadingDialog;
    public GameObject initPrefab;
    public AudioClip bgClip;
    public UILabel versionLabel;
    private LuaInterface.LuaTable self = null;

    static LuaInterface.LuaFunction getClassFun;
    LuaFramework.LuaManager luaMgr = LuaFramework.LuaManager.instance;

    GetLatestGameInfoResponse configResponse = null;
//    WindowProxy loadingDialogProxy;
    bool globalResInited;
    bool luaInited;
    DownloadWindowHelper downloadWindowHelper;

    static object ExternalResourceLoader(string path, System.Type t)
    {
        if (Login.CanUseExternalResource())
        {
            if(t == typeof(string) || t == typeof(byte[]))
            {
                byte[] data = ExternalResourceManager.GetBytes(path);
                if (data != null)
                {
                    if(t == typeof(string))
                    {
                        return System.Text.Encoding.UTF8.GetString(data);
                    }
                    
                    return data;
                }
            }
        }

        return null;
    }

    public static void GlobalInit()
    {
        if(!globalInited)
        {
            globalInited = true;

            Application.backgroundLoadingPriority = ThreadPriority.Low;
            Screen.sleepTimeout = SleepTimeout.NeverSleep;
            Application.targetFrameRate = LuaFramework.AppConst.GameFrameRate;



            MainThreadDispatcher.Init();
            CompressManager c = CompressManager.instance;

            UIDrawCall.externalLoader = LoadExternalShader;
            ResourceManager.externalResourceLoader = ExternalResourceLoader;

            // LangManager.externalLoader = LoadExternalLang;
            // SensitiveWordManager.externalLoader = LoadExternalLang;
            // NotchInfoManager.externalLoader = LoadExternalNotch;

            SerializableFieldContainerHelper.serializeListener = new MySerializeListener();
            
            bool enableSpriteSheet = !Application.isEditor;
            
            UnityEngine.U2D.SpriteAtlasManager.atlasRegistered += AtlasRegistered;
            UnityEngine.U2D.SpriteAtlasManager.atlasRequested += RequestAtlas;
                
            
            ResourcesEx.EnableSpriteSheet(enableSpriteSheet);

            AppInfo appInfo = GetAppInfo();


            // if (!UnityEngine.Application.isEditor && (VersionEx.compile_type != CompileType.dev))
            // {
            //     string platform = Application.platform.getPlatform().ToString();
            //     string buglyAppId = appInfo.platform_info[platform].third_party_info[VersionEx.compile_type.ToString()]["bugly_app_id"];
            // }

            // if (!Application.isEditor && VersionEx.compile_type != CompileType.release)
            // {
            //     Hdg.rdtDebug.s_logLevel = Hdg.rdtDebug.LogLevel.Debug;
            // }

            UnityEngine.Physics.queriesHitTriggers = false;
            UpdateGuiLog();
            LuaResLoader.debugPath = Application.persistentDataPath + "/" + VersionEx.version_number;
            SensitiveWordManager.showStar = VersionEx.compile_type == CompileType.release || VersionEx.compile_type == CompileType.beta;
        }
    }

    static void AtlasRegistered(UnityEngine.U2D.SpriteAtlas spriteAtlas)
    {
        Debug.LogErrorFormat("AtlasRegistered {0}.", spriteAtlas.name);
    }
    
    static void RequestAtlas(string tag, System.Action<UnityEngine.U2D.SpriteAtlas> callback)
    {
        var atlas = ResourceManager.LoadAsset<UnityEngine.U2D.SpriteAtlas>(ResourcesEx.SpriteAtlasDir + "/" + tag);
        Debug.LogErrorFormat("RequestAtlas {0} | {1}.", tag, atlas);
        callback(atlas);
    }

    static bool CanUseExternalResource()
    {
        if(ExternalResourceManager.GetMd5() != null)
        {
            BundleVersionConfig bundleVersionConfig = BundleVersionManager.instance.GetBundleVersionConfig();
            bool canUse = bundleVersionConfig == null || ExternalResourceManager.GetVersion() >= bundleVersionConfig.version;
            return canUse;
        }

        return false;
    }

    // static string LoadExternalLang(string path)
    // {
    //     byte[] data = LoadExternalBytes(path);
    //     if (data != null)
    //     {
    //         return System.Text.Encoding.UTF8.GetString(data);
    //     }
    //     return null;
    // }

    static Shader LoadExternalShader(string path)
    {
        return ResourceManager.LoadShader(path);
    }

    static string LoadExternalNotch(string path)
    {
        byte[] data = LoadExternalBytes(path);
        if (data != null)
        {
            return System.Text.Encoding.UTF8.GetString(data);
        }
        else
        {
            TextAsset textAsset = ResourceManager.LoadAsset<TextAsset>(path);
            if (textAsset != null)
            {
                return textAsset.text;
            }
        }
        return null;
    }

    public static byte[] LoadExternalBytes(string path)
    {
        if (Login.CanUseExternalResource())
        {
            byte[] data = ExternalResourceManager.GetBytes(path);
            if (data != null)
            {
                return data;
            }
        }

        return null;
    }

    public override void Init(LuaInterface.LuaTable _luaParam = null)
    {
        if (luaInited && globalResInited)
        {
            this.versionLabel.text = VersionEx.compile_type + "  " + VersionEx.version + "  " + VersionEx.version_number + "  " + BundleVersionManager.instance.GetVersion() + "  " + ExternalResourceManager.GetVersion();

            // ShowDontDestroyObjectsInHdg();
            
            AndroidHelper.SetEscapeCallback(OnEscape);

            this.loadingDialog.SetActive(false);
            base.Init(_luaParam);
        }
    }


    static void OnEscape()
    {
        if (exitWindowProxy != null)
        {
            return;
        }

        exitWindowProxy = RootWindowManager.instance.ShowWindow("TwoBtnDialog", RootWindowManager.alertDialogLayer9, false);
        exitWindowProxy.initedCallback = (winProxy) =>
            {
                UILabelEx content;
                UIButton okBtn;
                UIButton cancelBtn;
                GameObject blockClick;

                SerializableFieldContainerBehaviour fieldContainer = winProxy.win.GetComponent<SerializableFieldContainerBehaviour>();
                if(fieldContainer != null)
                {
                    FieldDictionary fieldDic = fieldContainer.GetFieldDictionary();
                    content = fieldDic.Get("content") as UILabelEx;
                    okBtn = fieldDic.Get("okBtn") as UIButton;
                    cancelBtn = fieldDic.Get("cancelBtn") as UIButton;
                    blockClick = fieldDic.Get("blockClick") as GameObject;
                }
                else
                {
                    TwoBtnDialog dialog = winProxy.winData as TwoBtnDialog;
                    content = dialog.content;
                    okBtn = dialog.okBtn;
                    cancelBtn = dialog.cancelBtn;
                    blockClick = dialog.blockClick;
                }

                content.SetText(TextKey.exit_prompt);
                UIEventListener.Get(okBtn.gameObject).onClick = (g) =>
                    {
                        winProxy.Close();
                        exitWindowProxy = null;
                        AndroidHelper.MoveTaskToBack();
                    };
                
                UIEventListener.Get(cancelBtn.gameObject).onClick = (g) =>
                    {
                        winProxy.Close();
                        exitWindowProxy = null;
                    };

                if(blockClick == null)
                {
                    blockClick = Window.CreateBlockClick(winProxy.win.gameObject, winProxy.win.GetPanel());
                }

                UIEventListener.Get(blockClick.gameObject).onClick = (g) =>
                    {
                        winProxy.Close();
                        exitWindowProxy = null;
                    };
            };
        exitWindowProxy.Init();
    }


    void Update()
    {
        if (this.downloadWindowHelper != null)
        {
            this.downloadWindowHelper.Update();
        }
    }

    void InitAssetBundle(System.Action<bool> callback)
    {
        if (SwitchConfig.isEnableHotFix)
        {
            BundleVersionManager.instance.Init((result) =>
                {
                    if(result)
                    {
                        ConsumeTime.Log("NewBundleManager.instance.SetVersionBundleConfig", () =>
                            {
                                NewBundleManager.instance.SetVersionBundleConfig(BundleVersionManager.instance.GetBundleVersionConfig(), this, () =>
                                    {
                                        callback(result);
                                    });
                            });
                    }
                    else
                    {
                        callback(result);
                    }
                });
        }
        else
        {
            callback(true);
        }
    }

    // public ServerInfo[] GetServerInfos()
    // {
    //     if (configResponse == null)
    //     {
    //         return null;
    //     }

    //     return configResponse.server_infos;
    // }

    public static string GetIP()
    {
        string ipAddress = "";
        foreach (NetworkInterface item in NetworkInterface.GetAllNetworkInterfaces())
        {
#if UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN
            NetworkInterfaceType _type1 = NetworkInterfaceType.Wireless80211;
            NetworkInterfaceType _type2 = NetworkInterfaceType.Ethernet;

            if ((item.NetworkInterfaceType == _type1 || item.NetworkInterfaceType == _type2) && item.OperationalStatus == OperationalStatus.Up)
#endif
            {
                foreach (UnicastIPAddressInformation ip in item.GetIPProperties().UnicastAddresses)
                {
                    //ipv4 地址
                    if (ip.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
                        ipAddress = ip.Address.ToString();
                    // ipv6 地址
                    //if (ip.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6)
                    //ipAddress = ip.Address.ToString();
                }
            }
                
        }
        return ipAddress;
    }

    // public void PlayRoleVideo(string videoName, LuaInterface.LuaTable luaTable)
    // {
    //     self = luaTable;
    //     BgSoundManager.instance.Clear();
    //     BgSoundManager.instance.Play(null, false);

    //     //MediaPlayerCtrlEx videoCtrl = videoMovie.GetComponent<MediaPlayerCtrlEx>();
    //     videoMovie.m_strFileName = videoName;
    //     videoMovie.OnEnd = OnEnd;
    //     videoMovie.OnVideoError = OnError;
    //     if (skipBtn != null)
    //     {
    //         UIEventListener.Get(skipBtn).onClick = OnSkipVideoClick;
    //     }
    //     //this.loginMovie.gameObject.SetActive(false);
    //     //this.loginMovie.enabled = false;
    //     videoMovie.gameObject.SetActive(true);
    //     videoMovie.enabled = true;
    // }

    void Awake()
    {
        Application.targetFrameRate = 60;

        this.versionLabel.text = VersionEx.compile_type + "  " + VersionEx.version + "  " + VersionEx.version_number + "  " + BundleVersionManager.instance.GetVersion() + "  " + ExternalResourceManager.GetVersion();
        
        SetLuaCtrlName("View/" + this.GetType().Name + "Ctrl");

        GlobalInit();

        if (!inited)
        {
            inited = true;
            SetLangFromSetting();

            GameObject.Instantiate(initPrefab);
            // ShowDontDestroyObjectsInHdg();

            FileLog.Init(Application.persistentDataPath + "/file_log.txt");
        }
        GotoLogin();
    }

    // void OnSkipVideoClick(GameObject obj)
    // {
    //     OnEnd();
    // }

    // void OnEnd()
    // {
    //     if (self != null)
    //     {
    //         getClassFun = luaMgr.lua.GetFunction("LoginWindowCtrl.OnCreatCallBack");
    //         getClassFun.BeginPCall();
    //         getClassFun.Push(self);
    //         getClassFun.PCall();
    //         getClassFun.EndPCall();
    //     }
    // }

    // void OnError(MediaPlayerCtrlEx.MEDIAPLAYER_ERROR error0, MediaPlayerCtrlEx.MEDIAPLAYER_ERROR error1)
    // {
    //     OnEnd();
    // }

    void GotoLogin()
    {
        this.loadingDialog.SetActive(true);

        //this.loginMovie.gameObject.SetActive(true);
        //this.loginMovie.enabled = true;

        // bool enableBg = PlayerPrefs.GetInt("enable_sound_bg", 1) != 0;
        // BgSoundManager.instance.EnableBg(enableBg, true);
        // BgSoundManager.instance.Clear();
        // BgSoundManager.instance.Play(this.bgClip, false);

        if(SwitchConfig.isEnableHotFix)
        {
            InitAssetBundle((result) =>
                {
                    CheckNewAssetBundle();
                });
        }
        else
        {
            CheckNewAssetBundleCallback(null, null, null, WebExceptionStatus.Success);
        }
    }



    // public static void InitBugly(string appId, bool isDebug)
    // {
    //     if (!Application.isMobilePlatform)
    //     {
    //         return;
    //     }
    //    BuglyAgent.ConfigAutoReportLogLevel(isDebug? LogSeverity.LogError: LogSeverity.LogException);
    //    BuglyAgent.ConfigDebugMode(isDebug);
    //    BuglyAgent.InitWithAppId(appId);
    //    BuglyAgent.EnableExceptionHandler();
    // }

    // public static void SetBuglyUserInfo(string userInfo)
    // {
    //     BuglyAgent.SetUserId(userInfo);
    // }

    // public static void InitGvoice(string appId, string appKey)
    // {
    //     if (!string.IsNullOrEmpty(VoiceManager.instance.appId))
    //     {
    //         return;
    //     }

    //     VoiceManager.instance.appId = appId;
    //     VoiceManager.instance.appKey = appKey;
    // }

//     public static void InitMiPush(string appId, string appKey)
//     {
// //        if (Application.isMobilePlatform)
// //        {
// //            #if UNITY_ANDROID
// //            MiPush.instance.registerPush(appId, appKey);
// //            #elif UNITY_IPHONE
// //            MiPush.__registerMiPush();
// //            #endif
// //        }
//     }

    public static void UpdateGuiLog()
    {
        UILogBehaviour.globalEnableShowLog = SwitchConfig.isEnableGuiLog;
    }

    static Dictionary<string, string> webServerInfos = null;
    public static string GetWebServerHost(string compileType)
    {
        if(webServerInfos == null)
        {
            TextAsset t = Resources.Load<TextAsset>("webserver");
            webServerInfos = JsonConvert.DeserializeObject<Dictionary<string, string>>(t.text);
        }

        return webServerInfos[compileType];
    }

    static AppInfo appInfo;
    public static AppInfo GetAppInfo()
    {
        if(appInfo == null)
        {
            TextAsset appInfoAsset = Resources.Load<TextAsset>("app_info");
            appInfo = JsonConvert.DeserializeObject<AppInfo>(appInfoAsset.text);
        }

        return appInfo;
    }

    void CheckNewAssetBundle()
    {
        this.loadingDialog.SetActive(true);

        if (BundleVersionManager.instance != null)
        {
            string bundleConfigMd5 = BundleVersionManager.instance.GetBundleConfigMd5();
            string urlHost = GetWebServerHost(VersionEx.compile_type.ToString());
			
            AppInfo appInfo = GetAppInfo();
			object request = HttpRequestManager.instance.CheckNewAssetBundle(urlHost + "/resource/getLatestResourceVersion", UnityEngine.SystemInfo.deviceUniqueIdentifier, appInfo.app_name, Application.platform.getPlatform().ToString(), AndroidHelper.isIl2cpp(), AndroidHelper.GetVersionNumber(), AndroidHelper.GetIl2cppPatchMd5(), VersionEx.compile_type.ToString(), VersionEx.version_number, bundleConfigMd5, CheckNewAssetBundleCallback, CheckNewAssetBundleParseDataCallback);
            string requestUrl = HttpRequestManager.instance.GetRequestUrl(request);
            
            Debug.Log("check resource version url: " + requestUrl);
        }
    }

    object CheckNewAssetBundleParseDataCallback(object request, byte[] data)
    {
        try
        {			
			string str = System.Text.Encoding.UTF8.GetString(data);
			
            GetLatestGameInfoResponse tempResponse = JsonConvert.DeserializeObject<GetLatestGameInfoResponse>(str);

            if (tempResponse.asset_bundle_info == null)
            {
                tempResponse.asset_bundle_info = new ResourceInfo();
            }

            return tempResponse;
        }
        catch (System.Exception e)
        {
            return e.Message;
        }
    }

    void CheckNewAssetBundleCallback(object request, object response, byte[] receiveData, WebExceptionStatus type)
    {
        string errMsg = null;
        int err = ErrorCode.NO_ERROR;
        if (type != WebExceptionStatus.Success)
        {
            errMsg = response as string;
            err = ErrorCode.UNKNOWN_ERROR;
        }
        else
        {
            if(receiveData != null && receiveData.Length != 0)
            {
                string str = System.Text.Encoding.UTF8.GetString(receiveData);
                
                            
                if (response is GetLatestGameInfoResponse)
                {
                    configResponse = response as GetLatestGameInfoResponse;
                    if (configResponse.error_code != ErrorCode.NO_ERROR)
                    {
                        errMsg = configResponse.error;
                        err = configResponse.error_code;
                    }
                }
                else
                {
                    errMsg = response as string;
                    err = ErrorCode.UNKNOWN_ERROR;
                }
            }
            else
            {

            }
        }

        if (err != ErrorCode.NO_ERROR || !string.IsNullOrEmpty(errMsg) || type != WebExceptionStatus.Success)
        {
            this.loadingDialog.SetActive(false);

            if(Application.isEditor)
            {
                Debug.LogError(type + "  |  " + errMsg + "  |  " + response);
            }

            WindowProxy proxy = RootWindowManager.instance.ShowWindow("TwoBtnDialog");
            proxy.initedCallback = (winProxy) =>
            {
                UILabelEx content;
                UIButton okBtn;
                UIButton cancelBtn;
                UILabelEx okBtnText;
                UILabelEx cancelBtnText;

                //                    UILabelEx okBtnText;
                //                    UIButton cancelBtn;
                //                    UILabelEx cancelBtnText;

                SerializableFieldContainerBehaviour fieldContainer = winProxy.win.GetComponent<SerializableFieldContainerBehaviour>();
                if(fieldContainer != null)
                {
                    FieldDictionary fieldDic = fieldContainer.GetFieldDictionary();
                    content = fieldDic.Get("content") as UILabelEx;
                    okBtn = fieldDic.Get("okBtn") as UIButton;
                    cancelBtn = fieldDic.Get("cancelBtn") as UIButton;
                    okBtnText = fieldDic.Get("okBtnText") as UILabelEx;
                    cancelBtnText = fieldDic.Get("cancelBtnText") as UILabelEx;

                    //                        okBtnText = fieldDic.Get("okBtnText") as UILabelEx;
                    //                        cancelBtn = fieldDic.Get("cancelBtn") as UIButton;
                    //                        cancelBtnText = fieldDic.Get("cancelBtnText") as UILabelEx;
                }
                else
                {
                    TwoBtnDialog dialog = winProxy.winData as TwoBtnDialog;
                    content = dialog.content;
                    okBtn = dialog.okBtn;
                    cancelBtn = dialog.cancelBtn;
                    okBtnText = dialog.okBtnText;
                    cancelBtnText = dialog.cancelBtnText;

                    //                        okBtnText = dialog.okBtnText;
                    //                        cancelBtn = dialog.cancelBtn;
                    //                        cancelBtnText = dialog.cancelBtnText;
                }

                    switch(err)
                    {
                        case ErrorCode.CLIENT_NEED_UPDATE:
                        {
                            okBtnText.text = "更新";
                            cancelBtnText.text = "退出";
                            string sizeStr = "1G";
#if UNITY_ANDROID
                            sizeStr = "300M";
#elif UNITY_IPHONE
                            sizeStr = "1G";
#endif
                            string tipText = "亲爱的玩家，全新版本现已发布，请重新下载安装包（约{0}）后再进行游戏）。\n给您造成的不便请谅解，《文明岔口》期待您的回归！\n建议WIFI环境更新。";
                            tipText = string.Format(tipText, sizeStr);
                            content.SetText(tipText);
                            UIEventListener.Get(okBtn.gameObject).onClick = (g) =>
                {
#if UNITY_ANDROID
                    Application.OpenURL("download_url");
#else
                    CheckNewAssetBundle();
                    winProxy.Close();
#endif
                };
                        }
                        break;
                        case ErrorCode.RECEIVE_ERROR_DATA:
                        {
                            content.SetText("服务器收到错误数据");
                        }
                        break;
                        default:
                        {
                            if(VersionEx.compile_type != CompileType.release && VersionEx.compile_type != CompileType.beta)
                            {
                                content.SetText(LangManager.Get(TextKey.connect_fail) +":" + type + ": " + (errMsg == null? errMsg: errMsg.Substring(0, 10)));  //返回错误信息
                            }
                            else
                            {
                                content.SetText(TextKey.connect_fail);  //返回错误信息
                            }
                        }
                        break;
                    }

                
                
                
                 UIEventListener.Get(cancelBtn.gameObject).onClick = (g) =>
                {
                    Application.Quit();
                };
            };
            proxy.Init();
        }
        else
        {
            if (!SwitchConfig.isEnableHotFix)
            {
                ConsumeTime.Log("CreateGlobalResource", () =>
                    {
                        RootWindowManager.instance.CreateGlobalResource(() => 
                            {
                                ConsumeTime.Log("Init", () =>
                                    {
                                        globalResInited = true;
                                        Init();
                                    });
                            });
                    });

                bool reInitLua = false;
                ConsumeTime.Log("StartLua", () =>
                    {
                        reInitLua = StartLua();
                    });

                if (reInitLua)
                {
                    SingleThreadStarter.StartSingleThread(() =>
                        {
                            LuaFramework.LuaManager.instance.ThreadInit();

                            MainThreadDispatcher.DispatchToMainThread(() =>
                                {
                                    ConsumeTime.Log("InitMainThreadLua", () =>
                                        {
                                            LuaFramework.LuaManager.instance.MainThreadInit();
                                        });

                                    luaInited = true;
                                    ConsumeTime.Log("Init", () =>
                                        {
                                            Init();
                                        });
                                });
                        });
                }
                else
                {
                    luaInited = true;
                    ConsumeTime.Log("Init", () =>
                        {
                            Init();
                        });
                }

                return;
            }

            configResponse.asset_bundle_info.config = BundleVersionManager.instance.GetLatestConfig(configResponse.asset_bundle_info.config);
            uint size = BundleVersionManager.instance.GetTotalNeedDownloadSize(configResponse.asset_bundle_info.config);
            uint decompressSize = BundleVersionManager.instance.GetTotalNeedDecompressSize(configResponse.asset_bundle_info.config);
            uint extenSize = configResponse.external_resource_info != null ? configResponse.external_resource_info.size : 0;
			uint il2cppPatchSize = configResponse.il2cpp_patch_info != null ? configResponse.il2cpp_patch_info.size : 0;
            if (size > 0 || decompressSize > 0 || extenSize > 0 || il2cppPatchSize > 0)
            {
                this.loadingDialog.SetActive(false);

                if(configResponse.asset_bundle_info.urls == null || configResponse.asset_bundle_info.urls.Length <= 0)
                {
                    WindowProxy proxy = RootWindowManager.instance.ShowWindow("OneBtnDialog", false);
                    proxy.initedCallback = (winProxy) =>
                        {
                            UILabelEx content;
                            UIButton okBtn;
                            UILabelEx okBtnText;

                            SerializableFieldContainerBehaviour fieldContainer = winProxy.win.GetComponent<SerializableFieldContainerBehaviour>();
                            if(fieldContainer != null)
                            {
                                FieldDictionary fieldDic = fieldContainer.GetFieldDictionary();
                                content = fieldDic.Get("content") as UILabelEx;
                                okBtn = fieldDic.Get("okBtn") as UIButton;
                                okBtnText = fieldDic.Get("okBtnText") as UILabelEx;
                            }
                            else
                            {
                                OneBtnDialog dialog = winProxy.winData as OneBtnDialog;
                                content = dialog.content;
                                okBtn = dialog.okBtn;
                                okBtnText = dialog.okBtnText;
                            }
                                    
                            content.SetText("还没开服,请稍等");
                            okBtnText.SetText("重试");
                            UIEventListener.Get(okBtn.gameObject).onClick = (g) =>
                            {
                                winProxy.Close();
                                CheckNewAssetBundle();
                            };
                        };
                    proxy.Init();
                    return;
                }

                //if (/* using wifi */ true)
                // ios审核需要： 提示下载包大小
                // if(Application.internetReachability == NetworkReachability.ReachableViaLocalAreaNetwork) //当用户使用wifi
                // {
                //     StartDownload();
                // }
                // else
                // {
                    // if (size <= 100 * 1024 * 1024)
                    // {
                    //     StartDownload();
                    // }
                    // else
                    if (size <= 0 && extenSize <= 0 && il2cppPatchSize <= 0)
                    {
                        StartDownload();
                    }
                    else
                    {
                        
                        WindowProxy proxy = RootWindowManager.instance.ShowWindow("OneBtnDialog", false);
                        proxy.initedCallback = (winProxy) =>
                            {
                                UILabelEx content;
                                UIButton okBtn;
                                UILabelEx okBtnText;
                                // UIButton cancelBtn;
                                // UILabelEx cancelBtnText;

                                SerializableFieldContainerBehaviour fieldContainer = winProxy.win.GetComponent<SerializableFieldContainerBehaviour>();
                                if(fieldContainer != null)
                                {
                                    FieldDictionary fieldDic = fieldContainer.GetFieldDictionary();
                                    content = fieldDic.Get("content") as UILabelEx;
                                    okBtn = fieldDic.Get("okBtn") as UIButton;
                                    okBtnText = fieldDic.Get("okBtnText") as UILabelEx;
                                    //cancelBtn = fieldDic.Get("cancelBtn") as UIButton;
                                    //cancelBtnText = fieldDic.Get("cancelBtnText") as UILabelEx;
                                }
                                else
                                {
                                    OneBtnDialog dialog = winProxy.winData as OneBtnDialog;
                                    content = dialog.content;
                                    okBtn = dialog.okBtn;
                                    okBtnText = dialog.okBtnText;
                                    //cancelBtn = dialog.cancelBtn;
                                    //cancelBtnText = dialog.cancelBtnText;
                                }
                                        
                                content.SetText(new LangString(TextKey.download_prompt02, CommonUtil.toSizeString(size + extenSize + il2cppPatchSize)));
                                okBtnText.SetText(TextKey.update_dt_once);
                                //cancelBtnText.SetText(TextKey.do_later);
                                UIEventListener.Get(okBtn.gameObject).onClick = (g) =>
                                {
                                    winProxy.Close();

                                    StartDownload();
                                };

                                // UIEventListener.Get(cancelBtn.gameObject).onClick = (g) =>
                                // {
                                //     winProxy.Close();

                                //     //exit game process
                                //     Application.Quit();
                                // };
                            };
                        proxy.Init();
                    }
                //}
            }
            else
            {
                //for bug begin https://issuetracker.unity3d.com/issues/ios-metal-gpu-hang-error-ioaf-code-3-in-xcode-console
//                if (Application.platform == RuntimePlatform.IPhonePlayer)
//                {
//                    HideDontDestroyObjectsInHdg();
//                    RootWindowManager.instance.HideAllWindow(true);
//                    RootWindowManager.instance.DestroyGlobalResource();
//                    SensitiveWordManager.Reset();
//                    LangManager.Reset();
//                    ResourcesEx.Reset();
//                    ResourceManager.Reset();
//                    ObjectPool.Reset();
//                    IAPManager.instance.Reset();
//                    DestroyLua();
//                    AndroidHelper.SetEscapeCallback(null);
//                }
                //for bug end


                ConsumeTime.Log("init all", () =>
                    {
                        ConsumeTime.Log("init bundle config1", () =>
                            {
                                BundleVersionManager.instance.SetBundleVersionConfig(configResponse.asset_bundle_info.config);

                            });

                        ConsumeTime.Log("init bundle config2", () =>
                            {
                                NewBundleManager.instance.SetVersionBundleConfig(BundleVersionManager.instance.GetBundleVersionConfig(), this, () =>
                                    {
                                        ConsumeTime.Log("DelOldBundles", () =>
                                            {
                                                BundleVersionManager.instance.DelOldBundles();
                                            });
                                        ConsumeTime.Log("CreateGlobalResource", () =>
                                            {
                                                RootWindowManager.instance.CreateGlobalResource(() => 
                                                    {
                                                        globalResInited = true;
                                                        ConsumeTime.Log("Init", () =>
                                                            {
                                                                Init();
                                                            });
                                                    });
                                            });

                                        bool reInitLua = false;
                                        ConsumeTime.Log("StartLua", () =>
                                            {
                                                reInitLua = StartLua();
                                            });

                                        if(reInitLua)
                                        {
                                            SingleThreadStarter.StartSingleThread(() =>
                                                {
                                                    LuaFramework.LuaManager.instance.ThreadInit();

                                                    MainThreadDispatcher.DispatchToMainThread(() =>
                                                        {
                                                            ConsumeTime.Log("InitMainThreadLua", () =>
                                                                {
                                                                    LuaFramework.LuaManager.instance.MainThreadInit();
                                                                });

                                                            luaInited = true;
                                                            ConsumeTime.Log("Init", () =>
                                                                {
                                                                    Init();
                                                                });
                                                        });
                                                });
                                        }
                                        else
                                        {
                                            luaInited = true;
                                            ConsumeTime.Log("Init", () =>
                                                {
                                                    Init();
                                                });
                                        }
                                    });
                            });
                    });
                
            }

        }
    }
        
    void StartDownload()
    {
        WindowProxy proxy = RootWindowManager.instance.ShowWindow("DownloadWindow");
        proxy.initedCallback = (winProxy) =>
            {
                downloadWindowHelper = new DownloadWindowHelper(winProxy);
                ConsumeTime.Log("StartDownload", () =>
                    {
                        downloadWindowHelper.StartDownload(configResponse.asset_bundle_info.urls, configResponse.asset_bundle_info.config, configResponse.external_resource_info != null?configResponse.external_resource_info.url: null, configResponse.external_resource_info != null? configResponse.external_resource_info.size: 0, configResponse.il2cpp_patch_info != null? configResponse.il2cpp_patch_info.urls: null, configResponse.il2cpp_patch_info != null? configResponse.il2cpp_patch_info.file_name: null, configResponse.il2cpp_patch_info != null? configResponse.il2cpp_patch_info.size: 0, DownloadCallback); 
                    });
            };
        proxy.Init();
    }

    void DownloadCallback(DownloadBundleError error, bool decompressSuccess)
    {
        if (error == DownloadBundleError.None && decompressSuccess)
        {
            downloadWindowHelper = null;
            
			if(Il2cppPatchDownloadManager.GetTotalSize() > 0)
			{
				WindowProxy proxy = RootWindowManager.instance.ShowWindow("OneBtnDialog", false);
				proxy.initedCallback = (winProxy) =>
                {
                    UILabelEx content;
                    UIButton okBtn;

                    SerializableFieldContainerBehaviour fieldContainer = winProxy.win.GetComponent<SerializableFieldContainerBehaviour>();
                    if(fieldContainer != null)
                    {
                        FieldDictionary fieldDic = fieldContainer.GetFieldDictionary();
                        content = fieldDic.Get("content") as UILabelEx;
                        okBtn = fieldDic.Get("okBtn") as UIButton;
                    }
                    else
                    {
                        OneBtnDialog dialog = winProxy.winData as OneBtnDialog;
                        content = dialog.content;
                        okBtn = dialog.okBtn;
                    }
                        

                    content.SetText("重启"); 
                    UIEventListener.Get(okBtn.gameObject).onClick = (g) =>
                        {
                            winProxy.Close();
							
							Bootstrap.reboot_app();
                        };
                };
				proxy.Init();
				
				return;
			}
			
            // HideDontDestroyObjectsInHdg();
            RootWindowManager.instance.HideAllWindow(true);
            RootWindowManager.instance.DestroyGlobalResource();
            SensitiveWordManager.Reset();
            LangManager.Reset();
            ResourcesEx.Reset();
            ResourceManager.Reset();
            ObjectPool.Reset();
            // IAPManager.instance.Reset();
            DestroyLua();
            AndroidHelper.SetEscapeCallback(null);

            BundleVersionConfig versionConfig = BundleDownloadManager.instance.GetBundleVersionConfig();
            BundleVersionManager.instance.SetBundleVersionConfig(versionConfig);

            this.loadingDialog.SetActive(true);

            SingleThreadStarter.StartSingleThread(() =>
                {
                    BundleVersionManager.instance.ResetDownloadedBundleHashMap();
                    BundleVersionManager.instance.DelOldBundles();

                    MainThreadDispatcher.DispatchToMainThread(() =>
                        {

                            //for bug end
                            ConsumeTime.Log("init all", () =>
                                {
                                    ConsumeTime.Log("init bundle config", () =>
                                        {
                                            NewBundleManager.instance.SetVersionBundleConfig(BundleVersionManager.instance.GetBundleVersionConfig(), this, () =>
                                                {
                                                    ConsumeTime.Log("CreateGlobalResource", () =>
                                                        {
                                                            RootWindowManager.instance.CreateGlobalResource(() => 
                                                                {
                                                                    globalResInited = true;
                                                                    ConsumeTime.Log("Init", () =>
                                                                        {
                                                                            Init();
                                                                        });
                                                                });
                                                        });

                                                    bool reInitLua = false;
                                                    ConsumeTime.Log("StartLua", () =>
                                                        {
                                                            reInitLua = StartLua();
                                                        });

                                                    if(reInitLua)
                                                    {
                                                        SingleThreadStarter.StartSingleThread(() =>
                                                            {
                                                                LuaFramework.LuaManager.instance.ThreadInit();

                                                                MainThreadDispatcher.DispatchToMainThread(() =>
                                                                    {
                                                                        ConsumeTime.Log("InitMainThreadLua", () =>
                                                                            {
                                                                                LuaFramework.LuaManager.instance.MainThreadInit();
                                                                            });

                                                                        luaInited = true;
                                                                        ConsumeTime.Log("Init", () =>
                                                                            {
                                                                                Init();
                                                                            });
                                                                    });
                                                            });
                                                    }
                                                    else
                                                    {
                                                        luaInited = true;
                                                        ConsumeTime.Log("Init", () =>
                                                            {
                                                                Init();
                                                            });
                                                    }
                                                });
                                        });
                                });
                        });
                });
        }
        else
        {
//            var exception = new System.Exception();
//            Debug.LogError("test_exc:" + decompressSuccess + "  " + exception);

            WindowProxy proxy = RootWindowManager.instance.ShowWindow("OneBtnDialog", false);
            proxy.initedCallback = (winProxy) =>
                {
                    UILabelEx content;
                    UIButton okBtn;
//                    UILabelEx okBtnText;
//                    UIButton cancelBtn;
//                    UILabelEx cancelBtnText;

                    SerializableFieldContainerBehaviour fieldContainer = winProxy.win.GetComponent<SerializableFieldContainerBehaviour>();
                    if(fieldContainer != null)
                    {
                        FieldDictionary fieldDic = fieldContainer.GetFieldDictionary();
                        content = fieldDic.Get("content") as UILabelEx;
                        okBtn = fieldDic.Get("okBtn") as UIButton;
//                        okBtnText = fieldDic.Get("okBtnText") as UILabelEx;
//                        cancelBtn = fieldDic.Get("cancelBtn") as UIButton;
//                        cancelBtnText = fieldDic.Get("cancelBtnText") as UILabelEx;
                    }
                    else
                    {
                        OneBtnDialog dialog = winProxy.winData as OneBtnDialog;
                        content = dialog.content;
                        okBtn = dialog.okBtn;
//                        okBtnText = dialog.okBtnText;
//                        cancelBtn = dialog.cancelBtn;
//                        cancelBtnText = dialog.cancelBtnText;
                    }
                        
                    string errorMsg = null;
                    if(VersionEx.compile_type != CompileType.release && VersionEx.compile_type != CompileType.beta)
                    {
                        errorMsg = error.ToString() + "  decompress_result:" + decompressSuccess;
//                        Debug.LogError("test_exc2:" + exception);
                    }
                    else
                    {
                        if(error != DownloadBundleError.None)
                        {
                            errorMsg = LangManager.Get(TextKey.download_failed);
                        }
                        else if(!decompressSuccess)
                        {
                            errorMsg = LangManager.Get(TextKey.decompress_failed);
                        }
                    }

                    content.SetText(errorMsg);  //错误
                    UIEventListener.Get(okBtn.gameObject).onClick = (g) =>
                        {
                            BundleVersionManager.instance.ResetDownloadedBundleHashMap();
                            downloadWindowHelper.StartDownload(configResponse.asset_bundle_info.urls, configResponse.asset_bundle_info.config, configResponse.external_resource_info != null?configResponse.external_resource_info.url: null, configResponse.external_resource_info != null? configResponse.external_resource_info.size: 0, configResponse.il2cpp_patch_info != null? configResponse.il2cpp_patch_info.urls: null, configResponse.il2cpp_patch_info != null? configResponse.il2cpp_patch_info.file_name: null, configResponse.il2cpp_patch_info != null? configResponse.il2cpp_patch_info.size: 0, DownloadCallback);

                            winProxy.Close();
                        };
                };
            proxy.Init();
        }
    }

    void DestroyLua()
    {
        LuaFramework.LuaManager.instance.Close();
    }

    bool StartLua()
    {
        if (LuaFramework.LuaManager.instance.lua != null)
        {
            return false;
        }

        LuaFramework.LuaManager.instance.InitStart(new MyLuaResLoader());
        return true;
    }

    void OnGUI()
    {
        if (SwitchConfig.isEnableGuiLog)
        {
            string log = "";

//            log += "app_version: " + Version.version + "\n";
            log += "app_version_number: " + VersionEx.version_number + "\n";
            log += "app_plataform: " + Application.platform.getPlatform() + "\n";
            log += "app_compile_type: " + VersionEx.compile_type + "\n";

            {
                BundleVersionConfig config = BundleVersionManager.instance.GetBundleVersionConfig();
                if (config != null)
                {
//                    log += "\n";
                    log += "config_version: " + config.version + "\n";
                    log += "config_md5: " + config.md5 + "\n";
                    log += "config_min_app_version: " + config.min_app_version + "\n";
                    log += "config_platform: " + config.platform + "\n";
                    log += "config_compile_type: " + config.compile_type + "\n";
//                    log += "config_build_time: " + config.build_time + "\n";
                }
            }
            {
                BundleVersionConfig config = BundleDownloadManager.instance.GetBundleVersionConfig();
                if (config != null)
                {
//                    log += "\n";
                    log += "download_config_version: " + config.version + "\n";
                    log += "download_config_md5: " + config.md5 + "\n";
                    log += "download_config_min_app_version: " + config.min_app_version + "\n";
                    log += "download_config_platform: " + config.platform + "\n";
                    log += "download_config_compile_type: " + config.compile_type + "\n";
//                    log += "download_config_build_time: " + config.build_time + "\n";
                }
            }
                
            log += "config_resouce_version: " + ExternalResourceManager.GetVersion() + "\n";
            bool hasDebugDir = false;
            if (LuaResLoader.Instance is LuaResLoader)
            {
                hasDebugDir = ((LuaResLoader)LuaResLoader.Instance).HasDebugDir();
            }
            log += "has_debug_dir: " + hasDebugDir + "\n";

            GuiUtil.Label(log, 10, LabelPos.L | LabelPos.T);
        }
    }

    static GameObject[] GetAllDontDestroyObjects()
    {
        List<GameObject> objs = new List<GameObject>();
        Transform[] transforms = GameObject.FindObjectsOfType<Transform>();
        for (int i = 0; i < transforms.Length; i++)
        {
            Transform t = transforms[i];
            if ((t.gameObject.scene.name == "DontDestroyOnLoad") && t.parent == null)
            {
                objs.Add(t.gameObject);
            }
        }

        return objs.ToArray();
    }

    // static void HideDontDestroyObjectsInHdg()
    // {
    //     GameObject[] objs = GetAllDontDestroyObjects();
    //     for (int i = 0; i < objs.Length; i++)
    //     {
    //         Hdg.RemoteDebugServer.RemoveDontDestroyOnLoadObject(objs[i]);
    //     }
    // }

    // public static void ShowDontDestroyObjectsInHdg()
    // {
    //     GameObject[] objs = GetAllDontDestroyObjects();
    //     for (int i = 0; i < objs.Length; i++)
    //     {
    //         Hdg.RemoteDebugServer.AddDontDestroyOnLoadObject(objs[i]);
    //     }
    // }

    public static void SetLang(SystemLanguage lang)
    {
        if (lang != SystemLanguage.Unknown)
        {
            PlayerPrefs.SetString("lang", lang.ToString());
        }
        else
        {
            PlayerPrefs.DeleteKey("lang");
        }
        
        SetLangFromSetting();
        UILabelEx.UpdateAll();
        UI2DSpriteEx.UpdateAll();
    }

    static void SetLangFromSetting()
    {
        string langStr = PlayerPrefs.GetString("lang");
        SystemLanguage lang = Application.systemLanguage;
        if (!string.IsNullOrEmpty(langStr))
        {
            lang = (SystemLanguage)System.Enum.Parse(typeof(SystemLanguage), langStr, true);
        }

        LangManager.SetLang(lang);
    }   
}





public class DownloadWindowHelper
{
    ViewProxy proxy;
    UIProgressBar progress;
    UILabelEx progressLabel;
    UILabelEx promptLabel;
    UI2DSpriteEx bg;


    BundleGroupDownloadTask task;
    uint lastProgress = 0;
    float lastProgressTime = 0;
    float speed = 0;
    NewDecompressLocalBundleHelper decompressHelper;

    System.Action<DownloadBundleError, bool> callback;

    bool decompressCallbacked;
    bool decompressResult;

    bool downloadCallbacked;
    DownloadBundleError downloadResult;
    uint completeSize = 0;

    uint downloadLuaSize;
    bool downloadLuaCallbacked;
    bool downloadLuaResult;

    bool downloadIl2cppPatchCallbacked;
    bool downloadIl2cppPatchResult;
	
    public DownloadWindowHelper(ViewProxy proxy)
    {
        this.proxy = proxy;

        SerializableFieldContainerBehaviour fieldContainer = proxy.win.GetComponent<SerializableFieldContainerBehaviour>();
        if(fieldContainer != null)
        {
            FieldDictionary fieldDic = fieldContainer.GetFieldDictionary();
            progress = fieldDic.Get("progress") as UIProgressBar;
            progressLabel = fieldDic.Get("progressLabel") as UILabelEx;
            promptLabel = fieldDic.Get("promptLabel") as UILabelEx;
            bg = fieldDic.Get("bg") as UI2DSpriteEx;
        }
        else
        {
            DownloadWindow win = proxy.winData as DownloadWindow;
            progress = win.progress;
            progressLabel = win.progressLabel;
            promptLabel = win.promptLabel;
            bg = win.bg;
        }
    }



    public void StartDownload(string[] urls, BundleVersionConfig versionConfig, string luaUrl, uint luaSize, string[] il2cppPatchUrls, string ilc2ppPatchFileName, uint il2cppPatchSize, System.Action<DownloadBundleError, bool> callback)
    {
        this.callback = callback;
        decompressCallbacked = false;
        downloadCallbacked = false;
		downloadLuaCallbacked = false;
		downloadIl2cppPatchCallbacked = false;
		
        BundleDownloadManager.instance.SetUrl(urls[0]);
        BundleDownloadManager.instance.SetRedirectHelper(new BundleHttpRedirectHelper(urls));
        BundleDownloadManager.instance.SetBundleVersionConfig(versionConfig);

        this.task = null;
        BundleGroupDownloadTask tempTask = new BundleGroupDownloadTask();
        tempTask.Start(null, DownloadCallback);
        this.proxy.win.StartCoroutine(tempTask.StartTask());
        this.task = tempTask;

        decompressHelper = new NewDecompressLocalBundleHelper();
        decompressHelper.Start(versionConfig, DecompressCallback);

        completeSize = 0;
        Dictionary<string, BundleInfo> needDecompressBundleMap = decompressHelper.GetNeedDecompressBundleMap();
        Dictionary<string, DownloadBundleTaskInfo> downloadTaskInfo = this.task.getDownloadTaskInfos();
        Dictionary<string, BundleInfo>.Enumerator e = versionConfig.bundles.GetEnumerator();
        while (e.MoveNext())
        {
            if ((needDecompressBundleMap == null || !needDecompressBundleMap.ContainsKey(e.Current.Key)) && (downloadTaskInfo == null || !downloadTaskInfo.ContainsKey(e.Current.Key)))
            {
                completeSize += e.Current.Value.size;
            }
        }

        downloadLuaSize = luaSize;
 
        if (!ExternalResourceManager.Download(luaUrl, luaSize, DownloadLuaCallback))
        {
            DownloadLuaCallback(true);
        }

		
		if(!Il2cppPatchDownloadManager.Start(il2cppPatchUrls, new BundleHttpRedirectHelper(il2cppPatchUrls), ilc2ppPatchFileName, il2cppPatchSize, Il2cppPatchDownloadCallback))
		{
			Il2cppPatchDownloadCallback(true);
		}
    }

    void Finish()
    {
        if (decompressCallbacked && downloadCallbacked && downloadLuaCallbacked && downloadIl2cppPatchCallbacked)
        {
            if (downloadResult == DownloadBundleError.None && (!downloadLuaResult || !downloadIl2cppPatchResult))
            {
                downloadResult = DownloadBundleError.DownloadFailed;
            }
            this.callback(downloadResult, decompressResult);
        }
    }

	void Il2cppPatchDownloadCallback(bool success)
    {
        downloadIl2cppPatchCallbacked = true;
        downloadIl2cppPatchResult = success;

        Finish();
    }
	
    void DownloadLuaCallback(bool success)
    {
        downloadLuaCallbacked = true;
        downloadLuaResult = success;

        Finish();
    }

    void DecompressCallback(bool success)
    {
        decompressCallbacked = true;
        decompressResult = success;

        Finish();
    }

    void DownloadCallback(DownloadBundleError error, bool useDownload)
    {
        downloadCallbacked = true;
        downloadResult = error;

        Finish();
    }

    public void Update()
    {
        if (task == null)
        {
            this.progress.value = 0;
            this.progressLabel.SetText("");
            return;
        }

        uint decompressTotal = 0;
        uint decompressProgress = decompressHelper.GetProgress(out decompressTotal);

        uint downloadLuaProgress = (uint)ExternalResourceManager.GetProgress();
        // if (downloadLuaCallbacked && downloadLuaResult)
        // {
            // downloadLuaProgress = downloadLuaSize;
        // }

		uint downloadIlc2ppPatchProgress = (uint)Il2cppPatchDownloadManager.GetProgress();
        // if (downloadIl2cppPatchCallbacked && downloadIl2cppPatchResult)
        // {
            // downloadIlc2ppPatchProgress = Il2cppPatchDownloadManager.GetTotalSize();
        // }
		
        uint downloadTotal = 0;
        uint downloadprogress = 0;
        task.getProgress(ref downloadTotal, ref downloadprogress);

        uint total = decompressTotal + downloadTotal + downloadLuaSize + Il2cppPatchDownloadManager.GetTotalSize();
        uint progress = decompressProgress + downloadprogress + downloadLuaProgress + downloadIlc2ppPatchProgress;

        total += completeSize;
        progress += completeSize;

        string percent = "0%";
        if (total != 0)
        {
            this.progress.value = (float)progress / total;
            percent = (int)(100.0f * progress / total) + "%";

            if (Time.time - lastProgressTime >= 1)
            {
                speed = (progress - lastProgress) / (Time.time - lastProgressTime);
                lastProgressTime = Time.time;
                lastProgress = progress;
            }
        }
        else
        {
            this.progress.value = 0;
            this.speed = 0;
        }
            
        LangString ss = new LangString(TextKey.update_progress_prompt, new LangString(decompressTotal == decompressProgress? TextKey.download: TextKey.decompression), CommonUtil.toSizeString(speed) + "/s", CommonUtil.toSizeString(progress, false), CommonUtil.toSizeString(total, false), percent);
        this.progressLabel.SetText(ss);

        LangString ss2 = new LangString(TextKey.download_prompt01, new LangString(decompressTotal == decompressProgress? TextKey.download: TextKey.decompression));
        this.promptLabel.SetText(ss2);

    }
}